-
Notifications
You must be signed in to change notification settings - Fork 81
[그리디] 서현진 Spring JPA (1차) 4,5,6 단계 미션 제출합니다. #200
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: nonactress
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 현진님 ㅠㅠ 어제 완료한다고 했는데 죄송합니다 ㅠㅠ 현진님도 새해 복 많이 받으세요 🙇♂️
우선 리뷰가 여러번 진행되지 못할 것 같아서 원래 규칙이 코멘트가10개 이하로 리뷰를 진행하는 것인데, 리뷰가 많이 늦은 관계로 코멘트를 많이 추가해놨어요
그리고 제가 JPA는 아직 자세히 공부한 영역은 아니기 때문에 다른 분들 리뷰도 보시면서 학습하시면 더 좋아보입니다~!
Q1. 엔티티 참조 방식 vs ID 직접 참조 방식 현재 Reservation 엔티티가 Member, Theme, Time 객체를 직접 참조하도록 엔티티화하였습니다. 이 방식은 JPA의 이점을 살릴 수 있지만, 도메인 간의 결합도가 높아지는 측면도 있는 것 같습니다. 서비스의 규모가 커질 경우에도 지금처럼 모든 연관관계를 객체 참조로 유지하는 것이 좋은 방법인지 궁금합니다!
서비스의 규모가 커지더라도 상황에 따라 둘 다 사용하는 편이에요
- 직접 참조: 서로 연관된 데이터인 경우 경우 (ex. Reservation은 Theme + Time를 무조건 조회해야 유의미한 데이터임)
- 간접 참조: 해당 객체가 가지고 있는 다른 정보랑 크게 연관이 없어서 id만 가져도 되는 경우 (ex. Member와 Theme의 관계)
회사에서도 같은 서비스인데 두가지 방법 모두 혼용하고 있어요
테스트 할 때 결합도가 높긴한데, 처음 테스트 데이터를 만드는 사람만 힘들지 이후에는 복붙이라 큰 생각을 안하는 것 같네요 🤣
Q2. 대기 순번 계산의 효율성 현재 내 예약 목록을 조회할 때마다 각 대기 건에 대해 COUNT 쿼리를 실행하여 실시간 순번을 계산하고 있습니다. 대기자가 많아질 경우 성능 부하를 어떤 방식으로 해결하면 좋을 지 궁금합니다!
음 대기자가 많다면 COUNT 쿼리문 대신 대기자 수도 컬럼에 저장할 수 있어보여요
그러면 쿼리문이 2개 나가는게 필요하겠네요 (대기 추가 → 대기자 수 + 1)
대신 여기의 문제점이 동시성 문제가 발생할 수 있다는 점인데요. 이를 해결하기위해 락을 걸거나, 재시도를 사용할 수 있어서 오히려 동시에 대기버튼을 누르는 사람이 많으면 성능이 안좋아질 수도 있어보여요
여기서 더 최적화를 한다면 쿼리문을 2개 나가는 것보다 1개만 나가는게 DB 시간도 줄일 수 있으니 대기자 수는 글로벌 캐시에 저장하고, 예약 대기만 DB에 저장하는 방식도 사용해볼만 합니다.
| return ResponseEntity.internalServerError() | ||
| .body(new ErrorResponse("오류가 발생했습니다.")); | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기 글 참고해서 설정해주시면 좋아요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 감사합니다!! 덕분에 편하게 적용했습니다!!
| if (memberRepository.findByEmail("admin").isEmpty()) { | ||
| Member admin = new Member("admin", "admin", "admin", "ADMIN"); | ||
| memberRepository.save(admin); | ||
| System.out.println("관리자 계정이 생성되었습니다."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
System.out.println 대신 로그를 사용해보는건 어떨까요?? (ex. Slf4j)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
수정하겠습니다!
반영 커밋 : 6d27e4c
| @Column(nullable = false) | ||
| private String role; | ||
|
|
||
| @Column(name = "deleted") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기만 이름을 명시해둔 이유가 있나요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
따로 이유는 없고 다른 필드들 nullable처리를 해서 이름도 이렇게 설정하는 구나 해서 넣어봤습니다!
| public void setDeleted(boolean deleted) { | ||
| this.deleted = deleted; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 삭제된걸 복구하는 작업은 거의 발생하지 않으니 deleted를 파라미터로 가질 이유는 없어보여요
- setter라는 네이밍을 사용하는 것보다 1번에 이어서 삭제됐다는 메서드 네이밍으로 가는게 좋습니다. 자바 미션때를 생각해보시면 좋아요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아아 넵 파라미터 값과 네이밍 수정해보겠습니다!!
반영 커밋 : 3a50097
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍👍
| import java.util.Optional; | ||
|
|
||
| @Repository | ||
| @Transactional(readOnly = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
클래스에 @Transactional(readOnly = true)로 선언한 이유는 무엇인가요??
왜냐하면 클래스에 @Transactional를 설정할 수도 있어보이는데 readOnly 옵션을 적용한걸 선택하셔서요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
다양한 코드를 적용 시켜보고 싶어서 readOnly= ture 를 사용해 보았습니다!!
따로 비약적인 성능의 개선이나 로직의 가독성의 향상은 없지만 스냅샷을 체크하지 않는 find 와 관련된 메소드들에 좋을 것 같아 적용시켜 봤습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그러면 클래스 위에 @Transactional(readOnly=true)로 설정하게 될 경우의 장단점은 뭐가 있다고 생각하시나요??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
장점
- dirtyChecking을 하지 않아 snapShot을 가지고 있지 않아 메모리 관리에 효율적입니다!
- db 수정이 없다는 것이 명시됨으로 가독성이 올라갑니다!
단점
- 클래스 설정으로 transactional(readOnly=true) 한 것을 보지 못하고 cud 작업을 하게 될 수 도 있습니다!
추가
실무에선 두개의 db를 이용한다...??
Master DB: 쓰기(Insert/Update/Delete) 전용
Slave DB: 읽기(Select) 전용
readOnly=true가 설정된 메서드는 알아서 Slave DB로 접속하게끔 인프라를 구성할 수 있어, 전체 시스템의 부하를 획기적으로 줄일 수 있다고 하는데 맞는지 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍👍 단점의 경우 좀 크리티컬 할 수 있는데요. CUD 작업을 서버 배포하고 나서야 알 수 있기 때문에 클래스단에 @Transactional 을 적용하는 방법도 있을 것 같아요. 저는 팀에서 메서드 위에 @Transactional, @Transactional(readOnly=true)를 붙이는게 암묵적 컨벤션이더라구요
실무에선 두개의 db를 이용한다...??
Master DB: 쓰기(Insert/Update/Delete) 전용
Slave DB: 읽기(Select) 전용
readOnly=true가 설정된 메서드는 알아서 Slave DB로 접속하게끔 인프라를 구성할 수 있어, 전체 시스템의 부하를 획기적으로 줄일 수 있다고 하는데 맞는지 궁금합니다!
알아서 접속하게 만드려면 코드단에서 AbstractRoutingDataSource를 구현해서 readOnly를 사용하는지 여부를 파악하는 메서드를 사용해야 readOnly true/false 옵션에 맞게 접속가능해요
보통 책에서는 읽기 요청 : 쓰기 요청 비율이 8:2, 9:1인 편이라고 하는데요
장점은 현진님 말씀처럼 부하도 분산할 수 있고, Master는 CUD 연산에만 집중할 수도 있긴해요
그리고 Master DB가 다운되어도 MMM 구조로 만들어져 있으면 Slave가 Master로 승격되어서 안전한 구조라고 알고 있어요
다만 단점은 Master에서 작업한 CUD도 결국 Slave로 반영해야하는데, 이때 비동기로 전달되어서 읽기 요청을 했는데 아직 Slave에서 데이터 반영이 되지 않은 상황이 발생할 수 있는 최종적 일관성을 지향하게 되어요
| @@ -1,5 +1,7 @@ | |||
| package roomescape.time; | |||
|
|
|||
| import jakarta.persistence.Entity; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기는 안쓰이는 import 문으로 보여요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 제거 해보겠습니다!!
반영 커밋 : 4252f96
| spring.datasource.username=sa | ||
| spring.datasource.password= | ||
|
|
||
| # SQL ???? ?? ???? (JPA? ?? ??) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요거 ????으로 되어 있는건 따로 의미가 있는 내용인건가요 ?_?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
따로 없습니다!! 정리해서 다시 푸쉬 하겠습니다!!!
|
|
||
| @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) | ||
| @DirtiesContext(classMode = DirtiesContext.ClassMode.BEFORE_EACH_TEST_METHOD) | ||
| @DataJpaTest |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DataJpaTest로 하게되면 어떤게 달라지는지 설명해주시면 좋아보여요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SpringBootTest + @DirtiesContext
전체 애플리케이션 컨텍스트를 로드합니다.
@service, @RestController, @component 등 프로젝트에 정의된 거의 모든 빈(Bean)을 생성하여 메모리에 올립니다.
테스트 격리를 위해 스프링 컨텍스트를 매번 재생성하므로 성능 오버헤드가 크게 존재합니다.
@DataJpaTest
- 오직 데이터베이스 레이어와 관련된 빈들만 선택적으로 로드합니다.
@entity, Repository, JdbcTemplate, EntityManager 등이 여기에 해당합니다. - 내장된 자동 롤백 기능 덕분에 컨텍스트 재시작 없이도 테스트 격리를 보장합니다.
| spring.sql.init.mode=never | ||
|
|
||
| # JPA/Hibernate ?? - ?? DDL ?? ??? | ||
| spring.jpa.hibernate.ddl-auto=create |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ddl-auto도 여러가지 종류가 있는데 찾아보시면 좋아보입니다
그리고 현재 상황에서는 create를 사용해야할지, 아니면 어떤 값을 사용해야할지 생각해보시고 저에게 알려주세요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ddl-auto 종류
create: 엔티티 클래스와 매핑되는 테이블을 자동으로 생성합니다. 기존 테이블이 존재하면 삭제(drop) 후 새롭게 생성합니다.
create-drop: create와 동일하게 기존 테이블 삭제 후 생성하지만, 애플리케이션 종료 시 테이블을 삭제합니다.
update: 테이블이 없으면 생성하며, 기존 테이블이 존재하면 삭제하지 않고 변경사항(컬럼 추가 등)만 반영합니다.
validate: DDL을 수행하지 않고 엔티티 클래스와 테이블이 정상 매핑되는지만 검사합니다. 불일치 시 예외를 발생시키고 종료합니다.
none(default): 아무런 작업도 수행하지 않습니다.
어떻게 가장 좋을까
현재 h2를 사용하고 있고 엔티티에 대한 필드 변화가 미션을 진행함에 있어 생길 수 도 있다고 생각하여 create가 가장 적합하다고 생각합니다!
다만 블로그를 찾아보니 db가 초기화 되는 것은 절대 테스트가 아니면 절대 존재해선 안되니 무조건 update나 validate만 사용한다는 것 같습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
create가 가장 적합하다고 생각합니다!
👍👍👍
다만 블로그를 찾아보니 db가 초기화 되는 것은 절대 테스트가 아니면 절대 존재해선 안되니 무조건 update나 validate만 사용한다는 것 같습니다!
네 요거는 아마 팀프로젝트 진행할 때 MySQL 사용하실텐데 이때 사용하시면 좋아보여요
| logging.level.org.hibernate.SQL=DEBUG | ||
| logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요거는 찾아보니 nextstep에 따로 적혀있지 않은 설정으로 보이는데 적용한 이유가 있나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sql 쿼리문들을 콘솔에서 보다 자세히 보여준다고 해서 적용해보았습니다!!!
logging.level.org.hibernate.SQL=DEBUG => sql쿼리 문들을 보여줍니다!! ( spring.jpa.show-sql=true 와 같은 역할을 하는 코드인 것 같습니다!!...)
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE => SQL 로그에 실제로 어떤 값들이 바인딩되고 있는지 함께 출력을 해줍니다!
|
요번 미션을 진행하며 다소 스프링에 대한 이해도가 떨어져서 제미나이를 많이 사용한 것이 화를 부른 것 같습니다! 요번 리뷰를 받으며 조금 더 생각해보고 커밋을 진행하는 자세가 필요할 것 같다는 생각이 들었습니다!! 정말 좋은 리뷰 감사합니다!! |
70825
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안녕하세요 현진님~ 미션 2개 동시에 진행하시느라 고생이 많으시네요 ㅠㅠ
한 번 코드 리포맷이 필요해보이는데, 아래처럼 사진처럼 reformat 처리해주면 사소한 코드 설정들은 전부 해결될 것 같아보여요
위 사진처럼 패키지에서 오른쪽 클릭을 하면 reformat code가 있는데 이걸 사용하면 해당 패키지 안에 있는 모든 클래스 코드를 깔끔하게 만들어줘요
요번 미션을 진행하며 다소 스프링에 대한 이해도가 떨어져서 제미나이를 많이 사용한 것이 화를 부른 것 같습니다! 요번 리뷰를 받으며 조금 더 생각해보고 커밋을 진행하는 자세가 필요할 것 같다는 생각이 들었습니다!! 정말 좋은 리뷰 감사합니다!!
현진님이 스프링에 이해가 부족하다고 느끼는 것과 같이, 저도 똑같이 제 스스로가 스프링에 대한 이해도가 부족하다고도 느끼는 편이라 이거는 몇 년 더 공부하는게 아닌이상 어쩔 수 없는 것 같아요~
그래서 어떻게 하면 스프링에 대한 이해도를 늘릴 수 있을까하면 현진님이 책도 읽어야하는 것도 있구요. 그외에 공부하는 부분에 AI를 적극적으로 활용해야하는데, 현진님이 AI를 사용할 때 비판적 사고를 가지고, 주도권을 가지는게 중요합니다 ( 읽으면 좋은 글 - https://yozm.wishket.com/magazine/detail/3231/ )
연차가 좀 있으신 분들은 AI가 없던 시절에도 과제가 주어지면 어떻게 코딩할지 대충 아니까 AI를 사용해도 전혀 문제 없는데요. 그런데 저랑 현진님처럼 연차가 낮거나 or 공부 시작한지 얼마되지 않았을 때는 너무 많은 작업을 AI에게 맡기게 되면 힘들어집니다
남들은 같은 시간에 공부해서 활용력과 사고력을 키웠는데, AI에게 너무 많이 의탁하는 사람들은 나중에도 스스로 해결책을 생각하지 못하게 된다는 스노우볼이 굴러가게 되는데요. 이게 큰 문제점이 당장은 눈에 안보이고, 빠르면 반년 늦으면 몇년 뒤에 눈에 보인다는게 큰 것 같아요
호오오옥시 별다른 비판적 사고 없이 수용하면서 사용하게 된다면 한 번 쯤은 고민해보시길 바래요~
저 같은 경우엔 GPT는 구글링하는 시간 줄여주는 용도 위주로 사용하고 있어가지고.. 개발이랑 전혀 관계 없는 질문이라 부끄럽긴한데 ㅋㅋ 이런 것도 물어보고, 제가 주도권을 잡아서 질문하는 것 같아요. 코딩도 비슷하게 코드를 GPT가 알려준다면 그중에 궁금한 일부 영역을 더 자세하게 물어보는 편이에요
코딩은 회사 노트북으로 물어봐서 보여드릴 링크 남아있는게 없네요 ㅋㅋㅋ..
남은 리뷰도 화이팅하시길 바랍니다~
| @@ -0,0 +1,42 @@ | |||
| package roomescape.infrastructure; | |||
|
|
|||
| import io.jsonwebtoken.*; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기는 이 글 참고하셔서 1번 설정처럼 IntelliJ 내부 설정 값 변경하시면 좋아보여요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵!! 덕분에 개발 환경이 쾌적해 지는 것 같습니다~~!!! 감사합니다ㅏㅏㅏ
|
|
||
| public boolean validateToken(String token) { | ||
| try { | ||
| Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token); | |
| Jws<Claims> claims = Jwts.parser() | |
| .setSigningKey(secretKey) | |
| .parseClaimsJws(token); |
사소한거긴한데 .을 기준으로 한줄에 최대한 하나씩 적어두는게 좋습니다요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아 메소드가 별로 길지 않은 것 같아 그냥 적었는데 확실히 . 기준으로 나누는 것이 가독성이 좋은 것 같습니다!!
반영 커밋 : e948375
| .header("Connection", "keep-alive") | ||
| .header("Keep-Alive", "timeout=60") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
요기 궁금한 부분이 있는데요
keep-alive 헤더 설정한 이유가 있나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/login 과 /login/check 이후에는 추가적으로 통신하는 작업이 거의 필수적이라고 생각해서 connection을 유지 할 수 있도록 해보았습니다!
| return password; | ||
| } | ||
| } | ||
| } No newline at end of file |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기 아직 적용이 안된 것 같은데 확인 부탁드려요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| .body(new ErrorResponse(e.getMessage())); | ||
| } | ||
|
|
||
| @ExceptionHandler(ChangeSetPersister.NotFoundException.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ChangeSetPersister.NotFoundException.class는 처음 보는 예외인데요
요거는 어디서 사용하나요?? 코드에 현진님이 따로 적용한 부분은 없어가지구요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기서 던져지는 예외가 NoSuchElementException인데 notfoundException으로 생각하고 바로 글로벌 핸들러에서 처리하려고 한 것 같습니다! 그래서 위 예외 ChangeSetPersister.NotFoundException.class는 Spring Data 프로젝트의 Cross-Store 기능을 위해 만들어졌다고 합니다!
- Cross-Store : 하나의 엔티티를 두 가지 이상의 데이터 저장소(예: 관계형 DB인 MySQL + NoSQL인 MongoDB)에 동시에 나누어 관리하는 기술입니다.
예외 상황
-
데이터 정합성 오류: 여러 DB에서 데이터를 모아 하나의 객체를 완성해야 하는데, 마땅히 있어야 할 특정 데이터가 한쪽 DB에서 사라졌을 때 발생합니다.
-
상태 동기화 실패: 두 저장소 간의 상태를 동기화하는 도중, 참조해야 할 원본 데이터가 존재하지 않을 때 시스템이 이 예외를 던집니다.
NotFoundException을 만들어서 원래 하려던 방향으로 다시 수정해보겠습니다!
반영 커밋 : 658a29b
| public void setDeleted(boolean deleted) { | ||
| this.deleted = deleted; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
setter 메서드는 전부 삭제하는게 좋아요
지금 현진님은 혼자 미션하지만, 나중에 팀플을 하게되거나 회사에서 일하게 될 때 온갖 곳에 쓰일 가능성이 높아서 코드 유지보수가 굉장히 어려워집니다 (클린코드 1장 - 나쁜 코드쪽 참조)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
명심하겠습니다!! setter 사용 금지 🚫
반영 커밋 : 42fe9b0
memberController 개행 정리 Co-authored-by: Dabeen Jeong <hello70825@gmail.com>
AI 어떻게 사용해할까.....???공유해주신 글을 읽어보며 느낀 점이 참 많고 생각해볼 부분이 많았습니다! 특히 내가 그냥 살아있는 프롬포트가 된 것 같다는 기분이 들 정도로 개발을 공부하는 사람으로서 어떤 점에서 차별화를 하고 고민을 해봐야 할까에 대한 주제를 던져주는 글인 것 같습니다! 리뷰어님 말씀 처럼 저만의 비판적 사고를 유지하며 AI를 하나의 도구 처럼 이용할 수 있도록 이젠 많이 의존을 안해보겠습니다! |
70825
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현진님 미션 기간 많이 늦어졌는데 넘넘 고생하셨어요~!!
다음 미션도 화이팅하시길 바랍니다~ 🥳🥳


다빈님 안녕하세요! 병오년, 새해 복 많이 받으세여~ 연초에 바쁜 와중에 코드 리뷰 해주셔서 감사합니다🚀🚀
이번 미션에서는 JPA 를 활용해서 예약 기능 생성 과 이미 예약된 시간대에 대해 사용자가 대기를 걸고 자신의 순번을 확인할 수 있는 예약 대기 시스템을 만들어보았습니다.
주요 변경된 파일
reservation/
Reservation- 회원(Member) 필드 추가 및 대기 상태와 분리된 예약 엔티티ReservationService- 예약/대기 생성 시 중복 검증 로직 및 내 예약 목록 통합 조회 로직 구현ReservationRepository- JPQL을 활용한 회원별 예약 조회 및 소프트 삭제 로직MyReservationResponse- 예약/대기 상태를 구분하고 순번을 포함하는 통합 응답 DTOreservation/waiting/
Waiting- 대기 신청 정보와 신청 시점(createdAt)을 저장하는 엔티티WaitingRepository- 실시간 대기 순번 계산(Rank) 및 중복 대기 검증을 위한 JPQL 로직 정의WaitingService- 예약 존재 여부에 따른 대기 전환 비즈니스 로직 정의WaitingController- 대기 신청(POST) 및 대기 취소(DELETE) API 정의WaitingWithRank- DB 조회 결과(Waiting)와 계산된 순위(Rank)를 함께 운반하기 위한 객체(4단계에서 한 dao-> repository로 바꾼 내용은 포함하지 않았습니다!)
미션 해결 방식
1. 별도 엔티티(
Waiting)를 통한 예약 대기 구현Reservation엔티티에 상태 필드를 추가하는 대신, 별도의Waiting엔티티를 생성하여 관심사를 분리하였습니다.2. 실시간 순번 계산 로직 (Rank)
rank컬럼을 DB에 저장하지 않고, 조회 시점에 자신보다 먼저 신청한 사람의 수(createdAt비교) 를 계산하여 반환합니다.질문
Q1. 엔티티 참조 방식 vs ID 직접 참조 방식
현재 Reservation 엔티티가 Member, Theme, Time 객체를 직접 참조하도록 엔티티화하였습니다. 이 방식은 JPA의 이점을 살릴 수 있지만, 도메인 간의 결합도가 높아지는 측면도 있는 것 같습니다. 서비스의 규모가 커질 경우에도 지금처럼 모든 연관관계를 객체 참조로 유지하는 것이 좋은 방법인지 궁금합니다!
Q2. 대기 순번 계산의 효율성 현재 내 예약 목록을 조회할 때마다 각 대기 건에 대해 COUNT 쿼리를 실행하여 실시간 순번을 계산하고 있습니다. 대기자가 많아질 경우 성능 부하를 어떤 방식으로 해결하면 좋을 지 궁금합니다!